package filter

import (
	"maps"
	"net/url"
	"slices"
	"time"

	"gitee.com/gousing/helper/internal"
)

// SliceStringFunc 自定义Func方法过滤string切片中的每一个元素
func SliceStringFunc(data []string, filterFn ...func(str string) string) []string {
	if len(data) == 0 {
		return []string{}
	}
	if len(filterFn) == 0 {
		return slices.Clone(data)
	}
	vf := make([]string, len(data))
	for k, v := range data {
		vf[k] = v
		if len(vf[k]) == 0 {
			continue
		}
		for _, callback := range filterFn {
			vf[k] = callback(vf[k])
			if len(vf[k]) == 0 {
				break
			}
		}
	}
	return vf
}

// SliceAnyFunc 自定义Func方法过滤any切片中的每一个字符串元素
func SliceAnyFunc(data []any, filterFn ...func(str string) string) []any {
	if len(data) == 0 {
		return []any{}
	}
	if len(filterFn) == 0 {
		return slices.Clone(data)
	}
	vf := make([]any, len(data))
	for k, v := range data {
		vf[k] = _filterAnyFunc(v, filterFn...)
	}
	return vf
}

// MapStringFunc 自定义Func方法过滤字符串map中的每一个元素
func MapStringFunc[K comparable](data map[K]string, filterFn ...func(str string) string) map[K]string {
	if len(data) == 0 {
		return map[K]string{}
	}
	if len(filterFn) == 0 {
		return maps.Clone(data)
	}
	vf := make(map[K]string, len(data))
	for k, v := range data {
		vf[k] = v
		if len(vf[k]) == 0 {
			continue
		}
		for _, callback := range filterFn {
			vf[k] = callback(vf[k])
			if len(vf[k]) == 0 {
				break
			}
		}
	}
	return vf
}

// MapAnyFunc 自定义Func方法过滤map中的每一个字符串元素
func MapAnyFunc[K comparable](data map[K]any, filterFn ...func(str string) string) map[K]any {
	if len(data) == 0 {
		return map[K]any{}
	}
	if len(filterFn) == 0 {
		return maps.Clone(data)
	}
	vf := make(map[K]any, len(data))
	for k, v := range data {
		switch vs := v.(type) {
		case string:
			vf[k] = vs
			if len(vs) == 0 {
				continue
			}
			for _, callback := range filterFn {
				vs = callback(vs)
				if len(vs) == 0 {
					break
				}
			}
			vf[k] = vs
		}
		vf[k] = _filterAnyFunc(v, filterFn...)
	}
	return vf
}

// _filterAnyFunc 自定义Func方法过滤slice/map/url.Values中的每一个字符串元素
func _filterAnyFunc(data any, filterFn ...func(str string) string) any {
	data = internal.UnderefVal(data)
	if data == nil {
		return data
	}
	switch vs := data.(type) {
	default:
		return data
	case string:
		if len(vs) == 0 {
			return vs
		}
		for _, callback := range filterFn {
			vs = callback(vs)
			if len(vs) == 0 {
				return vs
			}
		}
		return vs
	case map[string]any:
		return MapAnyFunc(vs, filterFn...)
	case map[bool]any:
		return MapAnyFunc(vs, filterFn...)
	case map[int]any:
		return MapAnyFunc(vs, filterFn...)
	case map[int8]any:
		return MapAnyFunc(vs, filterFn...)
	case map[int16]any:
		return MapAnyFunc(vs, filterFn...)
	case map[int32]any:
		return MapAnyFunc(vs, filterFn...)
	case map[int64]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uint]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uint8]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uint16]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uint32]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uint64]any:
		return MapAnyFunc(vs, filterFn...)
	case map[uintptr]any:
		return MapAnyFunc(vs, filterFn...)
	case map[float32]any:
		return MapAnyFunc(vs, filterFn...)
	case map[float64]any:
		return MapAnyFunc(vs, filterFn...)
	case map[time.Time]any:
		return MapAnyFunc(vs, filterFn...)
	case map[time.Duration]any:
		return MapAnyFunc(vs, filterFn...)
	case map[time.Month]any:
		return MapAnyFunc(vs, filterFn...)
	case map[time.Weekday]any:
		return MapAnyFunc(vs, filterFn...)
	case map[string]string:
		return MapStringFunc(vs, filterFn...)
	case map[bool]string:
		return MapStringFunc(vs, filterFn...)
	case map[int]string:
		return MapStringFunc(vs, filterFn...)
	case map[int8]string:
		return MapStringFunc(vs, filterFn...)
	case map[int16]string:
		return MapStringFunc(vs, filterFn...)
	case map[int32]string:
		return MapStringFunc(vs, filterFn...)
	case map[int64]string:
		return MapStringFunc(vs, filterFn...)
	case map[uint]string:
		return MapStringFunc(vs, filterFn...)
	case map[uint8]string:
		return MapStringFunc(vs, filterFn...)
	case map[uint16]string:
		return MapStringFunc(vs, filterFn...)
	case map[uint32]string:
		return MapStringFunc(vs, filterFn...)
	case map[uint64]string:
		return MapStringFunc(vs, filterFn...)
	case map[uintptr]string:
		return MapStringFunc(vs, filterFn...)
	case map[float32]string:
		return MapStringFunc(vs, filterFn...)
	case map[float64]string:
		return MapStringFunc(vs, filterFn...)
	case map[time.Time]string:
		return MapStringFunc(vs, filterFn...)
	case map[time.Month]string:
		return MapStringFunc(vs, filterFn...)
	case map[time.Weekday]string:
		return MapStringFunc(vs, filterFn...)
	case []string:
		return SliceStringFunc(vs, filterFn...)
	case []any:
		return SliceAnyFunc(vs, filterFn...)
	case map[string][]string:
		vf := make(map[string][]string, len(vs))
		for k, v := range vs {
			if len(v) == 0 {
				vf[k] = []string{}
			}
			for _, vv := range v {
				if len(vv) == 0 {
					vf[k] = append(vf[k], vv)
					continue
				}
				for _, callback := range filterFn {
					vv = callback(vv)
					if len(vv) == 0 {
						break
					}
				}
				vf[k] = append(vf[k], vv)
			}
		}
		return vf
	case url.Values: //like map[string][]string
		// 遍历vs
		vf := make(url.Values, len(vs))
		for k, v := range vs {
			if len(v) == 0 {
				vf.Set(k, "")
			}
			for _, vv := range v {
				if len(vv) == 0 {
					vf.Add(k, vv)
					continue
				}
				for _, callback := range filterFn {
					vv = callback(vv)
					if len(vv) == 0 {
						break
					}
				}
				vf.Add(k, vv)
			}
		}
		return vf
	}
}
